/*!  \file   error.h
	 \author HiddenSeeker
	 Describes a semantic analysis error, that can be printed
 */
#pragma once
#include <string>
#include "../core/abstractnode.h"
class OperatorNode;
/*! Location of node
 */
class Location
{
public:
        int Position;   //!< Position 
        int Line;  //!< Line
        std::string Filename;  //!<  Filename
public:
		/*! Takes a position of node, as self
			\param[in] n node
		 */
		inline Location(AbstractNode * n)
		{
			if (!n) { Position=-1;  Line=-1; }
			else
			{
			Position=n->position();
			Line=n->line();
			Filename=n->filename();
			}
		}
		/*! Prints a location
		 */
		void print()  {  printf("%s:%d:%d",Filename.c_str(),Line,Position); }
};
/*! Class of basic error
 */
class Error
{
 protected:
		  Location m_loc;  //!< Location of node
 public:
	     /*! Constructor
			 \param[in] n node, whose location is taken
		  */
		 Error(AbstractNode * n);
		 /*! Prints an error with location 
		  */
		 virtual void printWithPrelude();
		 /*! Custom abstract call for printing data
		  */
		 virtual void print()=0;
		 /*! Compares with other error
			 \param[in] o other error
			 \return true if error appeared before other error
		  */
	     bool operator<(const Error & o);
		 /*! Destructor
		  */
		 virtual ~Error();
};

/*! A redefinition of library class
 */
class LibraryClassRedefinitionError: public Error
{
 private:
		 std::string  m_name;
 public:
	     /*! A Library class redefinition error
			 \param[in] errorloc error location
			 \param[in] name     name of error
		  */
	     inline LibraryClassRedefinitionError(AbstractNode * errorloc,
											  const std::string & name): Error(errorloc)
	     {
			 m_name=name;
	     }

		 void print();
};
/*! A class redefinition error
 */
class DataRedefinitionError: public Error
{
 private:
		  std::string m_object_type;
		  std::string m_object_name;
		  Location    m_prev;
 public:
		  /*!  Redefinition error
			   \param[in] errorloc    error node location
			   \param[in] prevloc     previous definition location
			   \param[in] objecttype  object type
			   \param[in] objectname  object name
		   */
	      DataRedefinitionError(AbstractNode * errorloc, 
			                    AbstractNode * prevloc, 
								const std::string & objecttype,
								const std::string & objectname);

		  /*! Prints an error
		   */
		  void print();
};

/*!  Incorrect template arguments count
 */
class IncorrectTemplateArgumentCountError: public Error
{
 private:
		    std::string  m_name;    //!< Class name
			unsigned int m_needed;  //!< Needed template argument count
			unsigned int m_real;    //!< Real template argument count
 public:
		 IncorrectTemplateArgumentCountError(AbstractNode * inh,
			                                 std::string name,
											 unsigned int needed,
											 unsigned int real);
		 /*! Prints an error
		  */ 
		 void print();
};

/*! Class does not exists error
 */
class ClassDoesNotExistsError: public Error
{
 private:
	      std::string m_name; //!< Name of class
 public:
	     ClassDoesNotExistsError(AbstractNode * node, const std::string & name);
		 /*! Prints an error
		  */ 
		 void print();
};

/*! Inheritance loop error
 */
class InheritanceLoopError: public Error
{
 private:
		  std::vector<std::string>  m_loop;  //!< Detected loop
 public:
	     InheritanceLoopError(AbstractNode * node, const std::vector<std::string> & loop);
		 /*! Prints an error
		  */ 
		 void print();
};

/*!  Incorrect operator signature
 */
class IncorrectOperatorSignature: public Error
{
 private:
		unsigned int  m_needed;
		unsigned int  m_real;
		std::string  m_method;
 public:
	 IncorrectOperatorSignature(AbstractNode * node,const std::string & method, unsigned int n, unsigned int r);
		/*! Prints an error
		 */
		void print();
};

/*! Operator does not exists
 */
class OperatorDoesNotExists: public Error
{
 private:
		 std::string m_method;
		 std::string m_opname;
 public:
	     OperatorDoesNotExists(AbstractNode * node, 
			                   const std::string & method, 
							   const std::string & name);
		 /*! Prints an error
		 */
		 void print();
};


/*! Operator already defines error
 */
class OperatorAlreadyDefined: public Error
{
 private:
			std::string m_opname;
			std::vector<std::string> m_signature;
 public:
		  OperatorAlreadyDefined(AbstractNode * node,
								 const std::string & opname,
								 const std::vector<std::string> & sig);
		 /*! Prints an error
		 */
		 void print();
};
/*! Error, when operator is declared as a field
 */
class OperatorField: public Error
{
 private:
 public:	     
		 OperatorField(AbstractNode * node);
		 /*! Prints an error
		 */
		 void print();
};

/*! Error, when abstract method is deferred as frozen
 */ 
class AbstractFrozen: public Error
{
 private:
	       std::string m_methname;
 public:
		 AbstractFrozen(AbstractNode * node,const std::string & method);
		 /*! Prints an error
		  */
		 void print();
};

/*! Error, when redefinition of method is duplicated
 */
class DuplicateRedefinition: public Error
{
 private:
		 std::string m_method;
 public:
		 DuplicateRedefinition(AbstractNode * node, const std::string & method);
		 /*! Prints an error
		  */
		 void print();
};

class DuplicateRename: public Error
{
 private:
		 std::string m_oldname;
 public:
		 DuplicateRename(AbstractNode * node, const std::string & method);
		 /*! Prints an error
		  */
		 void print();
};

class EffectiveToAbstractReplace: public Error
{
 private:	
		std::string m_method;

 public:
	    EffectiveToAbstractReplace(AbstractNode * node, const std::string & method);
		/*! Prints an error
		 */
		void print();
};


class FrozenRedefinition: public Error
{
 private:
		 std::string m_method;
 public:
		 FrozenRedefinition(AbstractNode * node, const std::string & method);
		 /*! Prints an error
		  */
		 void print();
};

class  ImplicitRedefinition: public Error
{
 private:
	    std::string m_method;
 public:
	 ImplicitRedefinition(AbstractNode * node, const std::string & method);
     /*! Prints an error
	  */
	 void print();
};

class AbstractFrozenClass: public Error
{
 private:
		std::string  m_class_name;
 public:
	  AbstractFrozenClass(ClassNode * node);
	  /*! Prints an error
	   */
	  void print();
};

class ImplicitAbstractClass: public Error
{
 private:
		std::string  m_class_name;
 public:
	  ImplicitAbstractClass(ClassNode * node);
	  /*! Prints an error
	   */
	  void print();
};

class FrozenInherited: public Error
{
 private:
		std::string m_class_name;
 public:
	    FrozenInherited(ClassNode * node);
        /*! Prints an error
	    */
	    void print();
};

class MultipleInheritance: public Error
{
 private:
	   std::string m_class_name;
 public:
	   MultipleInheritance(ClassNode * node);
       /*! Prints an error
	    */
	   void print();
};

class RootClassDoesNotExists: public Error
{
private:
	    std::string m_class;
public:
	   RootClassDoesNotExists(const std::string & cname);
	   /*! Prints an error
	    */
	   void print();
};

class RootMethodDoesNotExists: public Error
{
private:
	    std::string m_name;
	    std::string m_proc;
public:
	   RootMethodDoesNotExists(ClassNode * node,const std::string & proc);
	   /*! Prints an error
	    */
	   void print();
};

class RootMethodHasIncorrectSignature: public Error
{
private:
	    std::string m_name;
	    std::string m_proc;
public:
	   RootMethodHasIncorrectSignature(ClassNode * node,const std::string & proc);
	   /*! Prints an error
	    */
	   void print();
};

class MethodDoesNotExists: public Error
{
private:
	std::string  m_node;
public:
	 MethodDoesNotExists(IdentifierNode * node);
	 MethodDoesNotExists(ConverterNode  * node);
	 /*! Prints an error
	  */
	 void print();
};

class ConstructorAlreadyDefined: public Error
{
private:
	 IdentifierNode * m_node;
public:
	 ConstructorAlreadyDefined(IdentifierNode * node);
	 /*! Prints an error
	  */
	 void print();
};

class ConverterIsNotConstructor: public Error
{ 
private:
	 ConverterNode * m_node;
public:
	 ConverterIsNotConstructor(ConverterNode * node);
	 /*! Prints an error
	  */
	 void print();
};

class TypeDoesNotExists: public Error
{
 private:
	 std::string m_typename;
 public:
	 TypeDoesNotExists(ClassTypeNode * node);
	 TypeDoesNotExists(AbstractNode * node, const std::string & type);

	 /*! Prints an error
	  */
	 void print();
};

class IncorrectConverterSignature: public Error
{
  private:
	  ConverterNode * m_node;
  public:
	 IncorrectConverterSignature(ConverterNode * node);
	 /*! Prints an error
	  */
	 void print();
};	

class NotEqualSignatureForConverter: public Error
{
  private:
	  ConverterNode * m_node;
  public:
	 NotEqualSignatureForConverter(ConverterNode * node);
	 /*! Prints an error
	  */
	 void print();
};	


class ConverterAlreadyDefined: public Error
{
 private:
	   std::string m_direction;
	   std::string m_type;
 public:
	 ConverterAlreadyDefined(ConverterNode * node);
	 /*! Prints an error
	  */
	 void print();
};

class VariableShadowing : public Error
{
 private:
	 std::string m_name;
 public:
	 VariableShadowing(AbstractNode * node, const std::string & name);
	 /*! Prints an error
	  */
	 void print();
};

class Warning : public Error
{
 private:

 public:
		inline Warning(AbstractNode * node) : Error(node)
		{
		}

		virtual ~Warning();
};

class LocalVariableShadowing : public Warning
{
 private:
	 std::string m_name;
 public:
	 LocalVariableShadowing(AbstractNode * node, const std::string & name);
	 /*! Prints an error
	  */
	 void print();
};

class FieldOrMethodDoesNotExists: public Error
{
 private:
	 std::string m_name;
	 std::string m_type;
 public:
	 FieldOrMethodDoesNotExists(AbstractNode * node, 
		                        const std::string & name,
						        const std::string & type);
	 /*! Prints an error
	  */
	 void print();
};

class LocalVariableNotFound : public Error
{
 private:
		 std::string name;
 public:
	  LocalVariableNotFound(IdentifierNode * node);
	  LocalVariableNotFound(AbstractNode * node,std::string name);
	 /*! Prints an error
	  */
	 void print();
};


class OperatorMakesNoSense : public Error
{
 private:
	     OperatorNode * m_node;
 public:
	   OperatorMakesNoSense(OperatorNode * node);
   	 /*! Prints an error
	  */
	 void print();
};

class ExpressionMakesNoSense : public Error
{
 private:
 public:
		ExpressionMakesNoSense(AbstractNode * node);
   	 /*! Prints an error
	  */
	 void print();
};

class LeftOperandIsNotLValue: public Error
{
 private:
 public:
	    LeftOperandIsNotLValue(AbstractNode * node);
		/*! Prints an error
		 */
		void print();
};

class NoResult: public Error
{
 public:
	     NoResult(AbstractNode * node);
		 /*! Prints an error
		  */
		 void print();
};

class IncompatibleTypes: public Error
{
 private:
		std::string m_type1;
		std::string m_type2;
 public:
	   IncompatibleTypes(AbstractNode * node, const std::string & type1, const std::string & type2);
		/*! Prints an error
		 */
		void print();
};

class ConvertConform: public Error
{
 private:
		std::string m_type1;
		std::string m_type2;

 public:
		ConvertConform(AbstractNode * node, const std::string & typefrom,const std::string & typeto);
		/*! Prints an error
		 */
		void print();
};

class MethodIsInaccessible: public Error
{
 private:
		  std::string m_name;
		  std::string m_className;
 public:
	 MethodIsInaccessible(AbstractNode * node, const std::string & name, const std::string & className);
	 /*! Prints an error
	  */
	 void print();
};

class FieldIsInaccessible: public Error
{
 private:
		  std::string m_name;
		  std::string m_className;
 public:
	 FieldIsInaccessible(AbstractNode * node, const std::string & name, const std::string & className);
	 /*! Prints an error
	  */
	 void print();
};

class AbstractPrecursorCall: public Error
{
 private:
		std::string m_name;
		std::string m_className;
 public:
	 AbstractPrecursorCall(AbstractNode * node, const std::string & name, const std::string & className );
	 /*! Prints an error
	  */
	 void print();
};

class IncorrectAmountOfArguments: public Error
{
 private:
	 int m_given;
	 int m_real;
 public:
	 IncorrectAmountOfArguments(AbstractNode * node, int given, int real);
	 /*! Prints an error
	  */
	 void print();
};


class NotAnAncestor: public Error
{
private:
	std::string m_ancestor;
	std::string m_class;
public:
	NotAnAncestor(AbstractNode * node, const std::string & ancestor, const std::string & className);
	 /*! Prints an error
	  */
	 void print();
};

class PrecursorCurrentCreation: public Error
{
 public:
	 PrecursorCurrentCreation(AbstractNode * node);
	 /*! Prints an error
	  */
	 void print();
};


class AbstractClassCreation: public Error
{
public:
	AbstractClassCreation(AbstractNode * node);
	 /*! Prints an error
	  */
	 void print();
};

class NotAConstructor: public Error
{
 private:
 public:
	 NotAConstructor(AbstractNode * node);
	 /*! Prints an error
	  */
	 void print();

};

class ConstructorIsInaccessible: public Error
{
 private:
		  std::string m_name;
		  std::string m_className;
 public:
	 ConstructorIsInaccessible(AbstractNode * node, const std::string & name, const std::string & className);
	 /*! Prints an error
	  */
	 void print();
};

class AbstractRoot: public Error
{
 public:
	 AbstractRoot(AbstractNode * node);
	 /*! Prints an error
	  */
	 void print();

};

class AbstractRootProcedure: public Error
{
 public:
	   AbstractRootProcedure(AbstractNode * node);
	   /*! Prints an error
 	    */
 	    void print();
};

class VoidUsedInExpression: public Error
{
 public:
	   VoidUsedInExpression(AbstractNode * node);
	   /*! Prints an error
 	    */
 	    void print();
};

class CommonAncestorNotFound: public Error
{
 public:
	   CommonAncestorNotFound(AbstractNode * node);
	   /*! Prints an error
 	    */
 	   void print();
};

class OperatorOverloadNotFound: public Error
{
 private:
		std::vector<std::string> m_vect;
		std::string m_class;
		std::string m_name;
 public:
	 OperatorOverloadNotFound(AbstractNode * nodem,const std::string & name, const std::string & className,
												   const std::string & sarg, const std::string & targ);
	 OperatorOverloadNotFound(AbstractNode * nodem,const std::string & name, const std::string & className,
												   const std::string & sarg);
	 OperatorOverloadNotFound(AbstractNode * nodem,const std::string & name, const std::string & className);

	  /*! Prints an error
 	   */
 	  void print();

};

/*! An error, thar represents a duplicate inheritance in a hierarchy
 */
class DuplicateInheritance: public Error
{
 private:
		 std::string m_classname;
		 std::string m_inherclassname;
 public:
		 /*! Constructs a new error
			 \param[in] node         node of class, where duplicate inheritance is found
		     \param[in] classname    name of class, where duplicate inheritance is detected
			 \param[in] inhclassname inherited class name
		  */
		 DuplicateInheritance(AbstractNode * node,const std::string & classname, const std::string inhclassname);

		 /*! Prints an error
		  */
		 void print();
};